Validacion formularios

Descripcion

Como validar campos de un formulario con reactive forms

Código de ejemplo
Preparacion

Primero en el archivo app.module.ts tenemos que importar el modulo ReactiveFormsModule:

import { ReactiveFormsModule } from '@angular/forms';

el código del archivo app.module.ts quedaría asi:

import { NgModule } from '@angular/core';
import { ReactiveFormsModule } from '@angular/forms';
import { BrowserModule } from '@angular/platform-browser';

import { AppComponent } from './app.component';
import { UserComponent } from './user/user.component';

@NgModule({
  declarations: [
    AppComponent,
    UserComponent
  ],
  imports: [
    BrowserModule,
    ReactiveFormsModule
  ],
  providers: [],
  bootstrap: [AppComponent]
})
export class AppModule { }
Metodo

Para mostrar la validación de formularios usaremos un unico componente user en el que tendremos un input de texto, sobre el que haremos la validacion de los datos introducidos.

El archivo del componente, user.component.ts, quedaría asi:

import { Component, OnInit } from '@angular/core';
import { FormControl, FormGroup, Validators } from '@angular/forms';

@Component({
  selector: 'app-user',
  templateUrl: './user.component.html',
  styleUrls: ['./user.component.css']
})
export class UserComponent implements OnInit {

  userForm: FormGroup = new FormGroup({});

  constructor() { }

  ngOnInit(): void {

    this.userForm = new FormGroup(
      {
        name: new FormControl( "Pepe", [Validators.required, Validators.minLength(4)])
    });
  }

  get name() {return this.userForm.get('name')!}

}

El archivo del template, user.component.html, quedaria asi:

<form [formGroup]="userForm">

<input type="text" formControlName="name" />

<div *ngIf="name.invalid && (name.dirty || name.touched)">

    <div *ngIf="name.errors?.['required']">
        Name is required.
    </div>
    <div *ngIf="name.errors?.['minlength']">
        Name must be at least 4 characters long.
    </div>
</div>

<p>Valor introducido: {{userForm.get('name')?.value}}<p>
</form>

Formulario con varios campos y boton deshabilitado

El siguiente es un ejemplo de un formulario con dos campos y un boton que esta deshabilitado hasta que todos los campos del formulario sean validos

El archivo del componente, user.component.ts, quedaría asi:

import { Component, OnInit } from '@angular/core';
import { FormControl, FormGroup, Validators } from '@angular/forms';

@Component({
  selector: 'app-user',
  templateUrl: './user.component.html',
  styleUrls: ['./user.component.css']
})
export class UserComponent implements OnInit {

  userForm: FormGroup;

  constructor() { }

  ngOnInit(): void {

    this.userForm = new FormGroup(
      {
        name: new FormControl( "Pepe", [Validators.required, Validators.minLength(4)]),
        edad: new FormControl("0", Validators.pattern("^[0-9]*$"))
    });
  }

  get nameg() {return this.userForm.get('name')!}
  get edad() {return this.userForm.get('edad')!}

}

El archivo del template, user.component.html, quedaria asi:

<form [formGroup]="userForm">

<input type="text" formControlName="name" />

<div *ngIf="nameg.invalid && (nameg.dirty || nameg.touched)">

    <div *ngIf="nameg.errors?.['required']">
        Name is required.
    </div>
    <div *ngIf="nameg.errors?.['minlength']">
        Name must be at least 4 characters long.
    </div>
</div>

<br/><br/>
<input type="text" formControlName="edad" />

<div *ngIf="edad.invalid && (edad.dirty || edad.touched)">

    <div *ngIf="edad.errors?.['pattern']">
        edad must be a number.
    </div>

</div>

<br><br>
<input type="button" [disabled]="userForm.invalid" value="Enviar">

<p>Nombre: {{userForm.get('name')?.value}}; Edad: {{userForm.get('edad')?.value}}<p>
</form>

Formulario e inputs en componentes distintos

Si estamos utilizando el formulario en un componente y los inputs en un componente a parte (un componente hijo).

Tendremos que incluir lo siguiente en la etiqueta @Component:

   viewProviders: [
    {
      provide: ControlContainer,
      useExisting: FormGroupDirective
    }
  ]

El código quedaría tal que así:

En caso de que queramos poner el código de las validaciones en el componente hijo tenemos que pasar al hijo el miembro del FormControl referente al input que va a validar.

En este caso sería nameInput el problema es que al intentar pasarlo directamente nos dará el siguiente error:

Type 'AbstractControl' is missing the following properties from type 'FormControl': registerOnChange, registerOnDisabledChange, _applyFormState

Para poder pasarlo tenemos que castearlo con tipo any:

[nameInput]="$any(this.memberForm.get('nameInput')!)

En el componente hijo tendríamos el input en el componente:

y el código de comprobación en el HTML:

Desactivar input

Para desactivar un campo podemos hacerlo de dos maneras, cuando lo iniciamos pasando el valor inicial tal que así:

{value: "mivalor" disabled: true}
this.userForm = new FormGroup(
{
    name: new FormControl( {value:"Pepe", disabled:true}, [Validators.required, Validators.minLength(4)]),
    edad: new FormControl("0", Validators.pattern("^[0-9]*$"))
});

O tambien llamando al metodo disable() del form control:

  this.userForm = new FormGroup(
  {
        name: new FormControl( "Pepe", [Validators.required, Validators.minLength(4)]),
        edad: new FormControl("0", Validators.pattern("^[0-9]*$"))
    });

    this.name.disable();
  }

  get name() {return this.userForm.get('name')!}
  get edad() {return this.userForm.get('edad')!}
Establecer campo invalido manualmente

Si queremos controlar la validez de un campo de manera manual lo podemos hacer con la funcion setErrors del formcontrol del campo, para establecerlo como invalido sería asi:

this.name.setErrors({incorrect: true})

Y para establecerlo como valido sería asi:

this.name.setErrors(null)

En ocasiones tendremos que establecer el campo como touched (para que el campo aparezca en rojo), para eso lo hacemos de esta manera:

this.name.markAsTouched();
Tags

Reactive | Forms | Validaciones | Validations | Angular